﻿Imports DotNetNuke.Services.Search
Imports DotNetNuke.Entities.Users
Imports Aricie.Services
Imports System.Reflection
Imports Aricie.DNN.Modules.LuceneSearch.Settings
Imports Aricie.DNN.Modules.LuceneSearch.UI

Namespace Aricie.DNN.Modules.LuceneSearch.Business
    Public Module SearchController

#Region "Public Methods"

        ''' <summary>
        ''' Get All Results by PortalId
        ''' </summary>
        ''' <param name="portalid"></param>
        ''' <param name="sorters"></param>
        ''' <param name="nbResultsFound"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function GetResults(ByVal portalid As Integer, ByVal sorters As String, ByRef nbResultsFound As Integer) As IList(Of LuceneSearchResultsInfo)
            Dim objQuery As New LuceneFilterQuery
            Dim objSearchParams As New SearchParams
            objSearchParams.LuceneFilterQuery = objQuery
            objSearchParams.SortField = sorters
            Return GetResults(portalid, -1, objSearchParams, nbResultsFound)
        End Function

        ''' <summary>
        ''' Get Search Results
        ''' </summary>
        ''' <param name="portalid">Portal ID</param>
        ''' <param name="moduleId">Module ID</param>
        ''' <param name="objQuery">Query Structure (Search and Filter)</param>
        ''' <param name="nbResultsFound">Numbers of results found</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function GetResults(ByVal portalid As Integer, ByVal moduleId As Integer, ByVal objQuery As LuceneFilterQuery, _
                                    ByRef nbResultsFound As Integer) As IList(Of LuceneSearchResultsInfo)
            Dim objSearchParams As New SearchParams
            objSearchParams.LuceneFilterQuery = objQuery
            Return GetResults(portalid, moduleId, objSearchParams, nbResultsFound)
        End Function

        ''' <summary>
        ''' Get Seach Results
        ''' </summary>
        ''' <param name="portalid">Portal ID</param>
        ''' <param name="moduleId">Module ID</param>
        ''' <param name="objQuery">Query Structure (Search and Filter)</param>
        ''' <param name="sorters"></param>
        ''' <param name="nbResultsFound"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function GetResults(ByVal portalid As Integer, ByVal moduleId As Integer, ByVal objQuery As LuceneFilterQuery, _
                            ByVal sorters As String, ByRef nbResultsFound As Integer) As IList(Of LuceneSearchResultsInfo)

            Dim objSearchParams As New SearchParams
            objSearchParams.LuceneFilterQuery = objQuery
            objSearchParams.SortField = sorters
            Return GetResults(portalid, moduleId, objSearchParams, nbResultsFound)
        End Function



        ''' <summary>
        '''  Get Search Results
        ''' </summary>
        ''' <param name="portalid">Portal ID</param>
        ''' <param name="moduleId">Module ID</param>
        ''' <param name="objSearchParam"></param>
        ''' <param name="nbResultsFound"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function GetResults(ByVal portalid As Integer, ByVal moduleId As Integer, _
                          ByVal objSearchParam As SearchParams, ByRef nbResultsFound As Integer) _
                         As IList(Of LuceneSearchResultsInfo)

            Dim toReturn As New List(Of LuceneSearchResultsInfo)

            Dim dataStore As SearchDataStoreProvider = SearchDataStoreProvider.Instance
            Dim allResults As SearchResultsInfoCollection
            Dim regularSorters As String = String.Empty

            If TypeOf (dataStore) Is LuceneSearchDataStore Then
                Dim results As LuceneQueryResults = DirectCast(dataStore, LuceneSearchDataStore).GetSearchResults(portalid, moduleId, objSearchParam)
                allResults = results.AsSearchResultsCollection(moduleId, True)
                nbResultsFound = results.NbResults
            Else
                allResults = dataStore.GetSearchResults(portalid, objSearchParam.LuceneFilterQuery.SearchQuery)
            End If
            Dim idxSearch As Integer = 0
            For Each toAdd As SearchResultsInfo In allResults
                If TypeOf toAdd Is LuceneSearchResultsInfo Then
                    Dim lsInfo As LuceneSearchResultsInfo = DirectCast(toAdd, LuceneSearchResultsInfo)
                    lsInfo.ResultIndex = idxSearch
                    toReturn.Add(lsInfo)
                Else
                    toReturn.Add(New LuceneSearchResultsInfo(moduleId, toAdd) With {.ResultIndex = idxSearch})
                End If
                idxSearch += 1
            Next
            
            Return toReturn

        End Function

        ''' <summary>
        ''' Get Results Count (Optimized Method, used by external modules)
        ''' </summary>
        ''' <param name="portalId"></param>
        ''' <param name="moduleId"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function GetResultsCount(ByVal portalId As Integer, ByVal moduleId As Integer) As Integer
            Dim objQuery As New LuceneFilterQuery
            Return GetResultsCount(portalId, moduleId, objQuery)
        End Function


        ''' <summary>
        ''' Get Results Count (Optimized Method, used by external modules)
        ''' </summary>
        ''' <param name="portalid"></param>
        ''' <param name="moduleId"></param>
        ''' <param name="objQuery"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function GetResultsCount(ByVal portalid As Integer, ByVal moduleId As Integer, ByVal objQuery As LuceneFilterQuery) As Integer
            Dim nbResultsFound As Integer
            Dim objSearchParams As New SearchParams
            objSearchParams.LuceneFilterQuery = objQuery
            objSearchParams.SortField = String.Empty
            objSearchParams.PageIndex = 0
            objSearchParams.PageSize = 1
            GetResults(portalid, moduleId, objSearchParams, nbResultsFound)
            Return nbResultsFound
        End Function

        ''' <summary>
        ''' Get Portal Documents
        ''' </summary>
        ''' <param name="portalId"></param>
        ''' <param name="nbResultsFound"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function GetPortalDocuments(ByVal portalId As Integer, ByRef nbResultsFound As Integer) As IList(Of LuceneSearchResultsInfo)

            Dim sorters As String = "TabId,ModuleId"
            Dim objQuery As New LuceneFilterQuery
            Return GetResults(portalId, -1, objQuery, sorters, nbResultsFound)

        End Function



#End Region

        

#Region "Obsolete Methods"

        <Obsolete("Please use the LuceneFilterQuery structure rather than 'Criteria' and 'Filter' string params")> _
        Public Function GetResults(ByVal portalid As Integer, ByVal moduleId As Integer, ByVal criteria As String, _
                               ByVal filter As String, ByRef nbResultsFound As Integer) As IList(Of LuceneSearchResultsInfo)

            Dim objLuceneQuery As New LuceneFilterQuery
            objLuceneQuery.SearchQuery = criteria
            If Not String.IsNullOrEmpty(filter) Then
                objLuceneQuery.FilterQuery = BusinessController.GetQuery(portalid, filter)
            End If
            Return GetResults(portalid, moduleId, objLuceneQuery, nbResultsFound)
        End Function


        <Obsolete("Please use the LuceneFilterQuery structure rather than 'Criteria' and 'Filter' string params and SearchParams Object rather than 'sorters' params ")> _
        Public Function GetResults(ByVal portalid As Integer, ByVal moduleId As Integer, ByVal criteria As String, _
                                   ByVal filter As String, ByVal sorters As String, ByRef nbResultsFound As Integer) As IList(Of LuceneSearchResultsInfo)
            Dim objLuceneQuery As New LuceneFilterQuery
            objLuceneQuery.SearchQuery = criteria
            If Not String.IsNullOrEmpty(filter) Then
                objLuceneQuery.FilterQuery = BusinessController.GetQuery(portalid, filter)
            End If

            Dim objSearchParams As New SearchParams
            objSearchParams.LuceneFilterQuery = objLuceneQuery
            objSearchParams.SortField = sorters
            Return GetResults(portalid, moduleId, objSearchParams, nbResultsFound)
        End Function

        <Obsolete("Please use the LuceneFilterQuery structure rather than 'Criteria' and 'Filter' string params and SearchParams Object rather than 'sorters','PageSize' and 'PageIndex' params")> _
        Public Function GetResults(ByVal portalid As Integer, ByVal moduleId As Integer, ByVal criteria As String, _
                                  ByVal filter As String, ByVal sorters As String, ByRef nbResultsFound As Integer, _
                                   ByVal resultPageIndex As Integer, ByVal pageSize As Integer) As IList(Of LuceneSearchResultsInfo)

            Dim objLuceneQuery As New LuceneFilterQuery
            objLuceneQuery.SearchQuery = criteria
            If Not String.IsNullOrEmpty(filter) Then
                objLuceneQuery.FilterQuery = BusinessController.GetQuery(portalid, filter)
            End If

            Dim objSearchParams As New SearchParams
            objSearchParams.LuceneFilterQuery = objLuceneQuery
            objSearchParams.SortField = sorters
            objSearchParams.PageIndex = resultPageIndex
            objSearchParams.PageSize = pageSize
            Return GetResults(portalid, moduleId, objSearchParams, nbResultsFound)

        End Function

        <Obsolete("Please use the LuceneFilterQuery structure rather than 'Criteria' and 'Filter' string params")> _
  Public Function GetResultsCount(ByVal portalid As Integer, ByVal moduleId As Integer, ByVal criteria As String, ByVal filter As String) As Integer
            Dim nbResultsFound As Integer

            Dim objLuceneQuery As New LuceneFilterQuery
            objLuceneQuery.SearchQuery = criteria
            If Not String.IsNullOrEmpty(filter) Then
                objLuceneQuery.FilterQuery = BusinessController.GetQuery(portalid, filter)
            End If

            Dim objSearchParams As New SearchParams
            objSearchParams.LuceneFilterQuery = objLuceneQuery
            objSearchParams.PageIndex = 0
            objSearchParams.PageSize = 1

            Dim tempResults As IList(Of LuceneSearchResultsInfo) = GetResults(portalid, moduleId, objSearchParams, nbResultsFound)
            Return nbResultsFound
        End Function

#End Region


    End Module

    Public Class SearchResultsComparer
        Implements IComparer(Of LuceneSearchResultsInfo)

        Private _fields As New Dictionary(Of String, Boolean)

        Sub New(ByVal expression As String)

            Dim expressions As String() = expression.TrimEnd(","c).Split(","c)
            For Each field As String In expressions
                Dim reverse As Boolean = field.StartsWith("-")
                Dim fieldName As String = field.TrimStart("-"c)

                _fields(fieldName) = reverse

            Next
        End Sub

        Public Function Compare(ByVal x As LuceneSearchResultsInfo, ByVal y As LuceneSearchResultsInfo) As Integer _
                                Implements IComparer(Of LuceneSearchResultsInfo).Compare

            Dim reverse As Boolean
            Dim aValue, bValue As IComparable

            For Each fieldName As String In _fields.Keys

                reverse = _fields(fieldName)

                aValue = x.Field(fieldName)
                bValue = y.Field(fieldName)

                If aValue Is Nothing And bValue IsNot Nothing Then
                    Return CInt(IIf(reverse, Integer.MaxValue, Integer.MinValue))
                ElseIf bValue Is Nothing AndAlso aValue IsNot Nothing Then
                    Return CInt(IIf(reverse, Integer.MinValue, Integer.MaxValue))
                End If
                Dim result As Integer = aValue.CompareTo(bValue)

                If result <> 0 Then
                    Return CInt(IIf(reverse, -result, result))
                End If

            Next

            Return 0

        End Function


    End Class

End Namespace
